package com.rtline.business.aop;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

import com.rtline.business.annotation.DistributedLock;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import cn.hutool.core.util.ReflectUtil;


/**
 * <p>DistributedLockAspect .
 *
 * <p>change history:
 *
 * <pre>
 * date         defect       person          comments
 * --------------------------------------------------------------------------------
 * 2025/6/1    ********     Tao Ren    create file.
 * </pre>
 *
 * @author Tao Ren
 * @date 2025/6/1 09:42
 */
@Aspect
@Component
public class DistributedLockAspect {

    @Autowired
    private RedissonClient redissonClient;

    @Around("@annotation(distributedLock)")
    public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable {
        // 解析SpEL表达式，生成锁的Key
        String lockKey = parseSpEL(joinPoint, distributedLock.key());

        RLock lock = redissonClient.getLock(lockKey);

        try {
            switch (distributedLock.lockType()) {
                case TRY_LOCK:
                    // 尝试获取锁
                    boolean isLocked = lock.tryLock(distributedLock.waitTime(), distributedLock.leaseTime(), TimeUnit.SECONDS);
                    if (!isLocked) {
                        throw new RuntimeException("获取分布式锁失败");
                    }
                    break;
                case LOCK:
                    // 直接获取锁
                    lock.lock();
                    break;
                default:
                    throw new IllegalStateException("Unexpected value: " + distributedLock.lockType());
            }
            // 执行目标方法
            return joinPoint.proceed();
        } finally {
            // 释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 解析SpEL表达式，生成锁的Key
     */
    private String parseSpEL(ProceedingJoinPoint joinPoint, String spEL) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String[] parameterNames = signature.getParameterNames();
        Object[] args = joinPoint.getArgs();

        StandardEvaluationContext context = new StandardEvaluationContext();
        for (int i = 0; i < parameterNames.length; i++) {
            context.setVariable(parameterNames[i], args[i]);
        }

        ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression(spEL);
        return expression.getValue(context, String.class);
    }
}
